package com.teradata.olingo.processor.core.api;

import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor;
import com.sap.olingo.jpa.metadata.api.JPAEdmProvider;
import com.teradata.olingo.processor.core.database.GenericDefaultDatabaseProcessor;
import com.teradata.olingo.processor.core.database.GenericODataDatabaseOperations;
import com.teradata.olingo.processor.core.database.GenericODataDatabaseProcessorFactory;
import com.teradata.olingo.processor.core.exception.ODataGenericFilterException;
import org.apache.olingo.commons.api.edmx.EdmxReference;
import org.apache.olingo.commons.api.ex.ODataException;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.debug.DebugSupport;
import org.apache.olingo.server.api.debug.DefaultDebugSupport;
import org.apache.olingo.server.api.processor.ErrorProcessor;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

final class GenericODataContextImpl implements GenericODataCRUDContext, GenericODataSessionContextAccess {
  /**
   * 
   */
  private final GenericODataGetHandler genericODataGetHandler;
  private List<EdmxReference> references = new ArrayList<>();
  private GenericODataGetHandler.JPADebugSupportWrapper debugSupport;
  private GenericODataDatabaseOperations operationConverter;
  private JPAEdmProvider jpaEdm;
  private GenericODataDatabaseProcessor databaseProcessor;
  private GenericServiceDebugger debugger;
  private JPAEdmMetadataPostProcessor postProcessor;
  private GenericCUDRequestHandler jpaCUDRequestHandler;
  private String[] packageName;
  private ErrorProcessor errorProcessor;
  private GenericODataPagingProvider pagingProvider;

  public GenericODataContextImpl(GenericODataGetHandler genericODataGetHandler) throws ODataException {
    super();
    this.genericODataGetHandler = genericODataGetHandler;
    this.debugSupport = this.genericODataGetHandler.new JPADebugSupportWrapper(new DefaultDebugSupport());
    operationConverter = new GenericDefaultDatabaseProcessor();
    try {
      databaseProcessor = new GenericODataDatabaseProcessorFactory().create(this.genericODataGetHandler.ds);
    } catch (SQLException e) {
      throw new ODataGenericFilterException(e, HttpStatusCode.INTERNAL_SERVER_ERROR);
    }

  }

  @Override
  public GenericCUDRequestHandler getCUDRequestHandler() {
    return jpaCUDRequestHandler;
  }

  @Override
  public GenericODataDatabaseProcessor getDatabaseProcessor() {
    return databaseProcessor;
  }

  @Override
  public GenericServiceDebugger getDebugger() {
    return debugger;
  }

  @Override
  public DebugSupport getDebugSupport() {
    return debugSupport;
  }

  @Override
  public JPAEdmProvider getEdmProvider() throws ODataException {
    if (jpaEdm == null)
      jpaEdm = new JPAEdmProvider(this.genericODataGetHandler.namespace, this.genericODataGetHandler.jpaMetamodel,
          postProcessor, packageName);
    return jpaEdm;
  }

  public ErrorProcessor getErrorProcessor() {
    return this.errorProcessor == null ? new GenericDefaultErrorProcessor() : this.errorProcessor;
  }

  @Override
  public GenericODataDatabaseOperations getOperationConverter() {
    return operationConverter;
  }

  @Override
  public String[] getPackageName() {
    return packageName;
  }

  @Override
  public List<EdmxReference> getReferences() {
    return references;
  }

  @Override
  public GenericODataPagingProvider getPagingProvider() {
    return pagingProvider;
  }

  @Override
  public void initDebugger(final String debugFormat) {
    // see org.apache.olingo.server.core.debug.ServerCoreDebugger
    boolean isDebugMode = false;

    if (debugSupport != null) {
      // Should we read the parameter from the servlet here and ignore multiple parameters?
      if (debugFormat != null) {
        debugSupport.init(this.genericODataGetHandler.odata);
        isDebugMode = debugSupport.isUserAuthorized();
      }
      if (isDebugMode)
        debugger = new GenericCoreDeugger();
      else
        debugger = new GenericEmptyDebugger();
      debugSupport.setDebugger(debugger);
    }
  }

  @Override
  public void setCUDRequestHandler(GenericCUDRequestHandler jpaCUDRequestHandler) {
    this.jpaCUDRequestHandler = jpaCUDRequestHandler;
  }

  @Override
  public void setDatabaseProcessor(final GenericODataDatabaseProcessor databaseProcessor) {
    this.databaseProcessor = databaseProcessor;
  }

  @Override
  public void setDebugSupport(final DebugSupport jpaDebugSupport) {
    this.debugSupport = this.genericODataGetHandler.new JPADebugSupportWrapper(jpaDebugSupport);
  }

  @Override
  public void setErrorProcessor(ErrorProcessor errorProcessor) {
    this.errorProcessor = errorProcessor;
  }

  @Override
  public void setMetadataPostProcessor(final JPAEdmMetadataPostProcessor postProcessor) throws ODataException {
    if (this.genericODataGetHandler.jpaMetamodel != null)
      jpaEdm = new JPAEdmProvider(this.genericODataGetHandler.namespace, this.genericODataGetHandler.jpaMetamodel,
          postProcessor, packageName);
    else
      this.postProcessor = postProcessor;
  }

  @Override
  public void setOperationConverter(final GenericODataDatabaseOperations jpaOperationConverter) {
    operationConverter = jpaOperationConverter;
  }

  @Override
  public void setReferences(final List<EdmxReference> references) {
    this.references = references;
  }

  @Override
  public void setTypePackage(final String... packageName) {
    this.packageName = packageName;

  }

  @Override
  public void setPagingProvider(final GenericODataPagingProvider provider) {
    this.pagingProvider = provider;
  }
}